gdkwindow: Use toplevel for getting root cords in move_to_rect()
authorJonas Ådahl <jadahl@gmail.com>
Thu, 4 Aug 2016 05:56:15 +0000 (13:56 +0800)
committerMatthias Clasen <mclasen@redhat.com>
Thu, 18 Aug 2016 08:51:57 +0000 (04:51 -0400)
The Wayland backend manages a set of fake root coordinate spaces, where
each non-relative positioned toplevel (i.e. not popups, popovers,
tooltips etc) make up the basis of separate fake root coordinate spaces.

This means that the Wayland backend doesn't have the abilitiy get a
proper root coordinate when querying on a non-toplevel GdkWindow. To
avoid this issue, first find the toplevel, while translating the anchor
rect coordinates so that they are in the toplevel window coordinate
space. Then use this toplevel to translate the coordinates to root
window coordinate space.

https://bugzilla.gnome.org/show_bug.cgi?id=769402

gdk/gdkwindowimpl.c

index 11e49d5bc7ff06263503e7bb0e0d5d0bb2583e67..c42c5aa2185e40c86d7dd0e8914f90b4d1e82053 100644 (file)
@@ -173,6 +173,29 @@ maybe_flip_position (gint      bounds_pos,
   return primary;
 }
 
+static GdkWindow *
+traverse_to_toplevel (GdkWindow *window,
+                      gint       x,
+                      gint       y,
+                      gint      *toplevel_x,
+                      gint      *toplevel_y)
+{
+  GdkWindow *parent;
+  gdouble xf = x;
+  gdouble yf = y;
+
+  while ((parent = gdk_window_get_effective_parent (window)) != NULL &&
+         (gdk_window_get_window_type (parent) != GDK_WINDOW_ROOT))
+    {
+      gdk_window_coords_to_parent (window, xf, yf, &xf, &yf);
+      window = parent;
+    }
+
+  *toplevel_x = (gint) xf;
+  *toplevel_y = (gint) yf;
+  return window;
+}
+
 static void
 gdk_window_impl_move_to_rect (GdkWindow          *window,
                               const GdkRectangle *rect,
@@ -182,6 +205,7 @@ gdk_window_impl_move_to_rect (GdkWindow          *window,
                               gint                rect_anchor_dx,
                               gint                rect_anchor_dy)
 {
+  GdkWindow *transient_for_toplevel;
   GdkDisplay *display;
   GdkMonitor *monitor;
   GdkRectangle bounds;
@@ -191,7 +215,18 @@ gdk_window_impl_move_to_rect (GdkWindow          *window,
   gboolean flipped_x;
   gboolean flipped_y;
 
-  gdk_window_get_root_coords (window->transient_for,
+  /*
+   * First translate the anchor rect to toplevel coordinates. This is needed
+   * because not all backends will be able to get root coordinates for
+   * non-toplevel windows.
+   */
+  transient_for_toplevel = traverse_to_toplevel (window->transient_for,
+                                                 root_rect.x,
+                                                 root_rect.y,
+                                                 &root_rect.x,
+                                                 &root_rect.y);
+
+  gdk_window_get_root_coords (transient_for_toplevel,
                               root_rect.x,
                               root_rect.y,
                               &root_rect.x,